﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Cdy.Tag;

namespace DBHighApi
{
    public class SecurityManager
    {

        #region ... Variables  ...
        /// <summary>
        /// 
        /// </summary>
        public static SecurityManager Manager = new SecurityManager();

        private Dictionary<string, List<string>> mUserReaderPermissionCach = new Dictionary<string, List<string>>();


        private Dictionary<string, List<string>> mUserWriterPermissionCach = new Dictionary<string, List<string>>();

        /// <summary>
        /// 
        /// </summary>
        private Dictionary<string, bool> mSuperUsers = new Dictionary<string, bool>();

        private Dictionary<long, Dictionary<int, bool>> mTagAllowedCached = new Dictionary<long, Dictionary<int, bool>>();


        #endregion ...Variables...

        #region ... Events     ...

        #endregion ...Events...

        #region ... Constructor...

        #endregion ...Constructor...

        #region ... Properties ...

        #endregion ...Properties...

        #region ... Methods    ...

        /// <summary>
        /// 判断是否拥有访问变量权限
        /// </summary>
        /// <param name="lid"></param>
        /// <param name="tagid"></param>
        /// <param name="enableWrite"></param>
        /// <returns></returns>
        public bool CheckHasPermission(long lid,int tagid,bool enableWrite)
        {
            if(mTagAllowedCached.ContainsKey(lid))
            {
                if (mTagAllowedCached[lid] == null)
                {
                    return true;
                }
                else 
                {
                    if (!enableWrite)
                        return  mTagAllowedCached[lid].ContainsKey(tagid);
                    else
                    {
                        return mTagAllowedCached[lid].ContainsKey(tagid) && mTagAllowedCached[lid][tagid];
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="lid"></param>
        public void BuildTagCached(long lid)
        {
            var user = ServiceLocator.Locator.Resolve<IRuntimeSecurity>().GetUserByLoginId(lid);
            if(!string.IsNullOrEmpty(user))
            {
                var pps = ServiceLocator.Locator.Resolve<IRuntimeSecurity>().GetPermission(user);
                if(pps!=null)
                {
                    bool isall = false;
                    List<UserPermission> groups = new List<UserPermission>();
                    foreach(var vv in pps)
                    {
                        if(vv.SuperPermission)
                        {
                            isall = true;
                        }
                        else
                        {
                            groups.Add(vv);
                        }
                    }
                    var mm = Cdy.Tag.ServiceLocator.Locator.Resolve<Cdy.Tag.ITagManager>();
                    if (isall)
                    {
                        mTagAllowedCached.Add(lid, null);
                    }
                    else
                    {
                        Dictionary<int,bool> bb = new Dictionary<int,bool>();
                        foreach(var vv in groups.Distinct())
                        {
                            foreach (var vvv in vv.Group)
                            {
                                var vtags = mm.GetTagsByGroup(vvv);
                                if (vtags != null)
                                {
                                    foreach (var vv2 in vtags)
                                    {
                                        if (bb.ContainsKey(vv2.Id))
                                        {
                                            if(vv.EnableWrite)
                                            {
                                                bb[vv2.Id] = true;
                                            }
                                        }
                                        else
                                        {
                                            bb.Add(vv2.Id, vv.EnableWrite);
                                        }
                                    }
                                }
                            }
                        }
                        mTagAllowedCached.Add(lid,bb);
                    }
                }
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool IsLogin(string token)
        {
            return ServiceLocator.Locator.Resolve<IRuntimeSecurity>().CheckLogin(token);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="token"></param>
        /// <param name="group"></param>
        /// <returns></returns>
        public bool CheckWritePermission(string token, string group)
        {
            var securityService = ServiceLocator.Locator.Resolve<IRuntimeSecurity>();

            var user = securityService.GetUserByLoginId(token);
            lock (mSuperUsers)
            {
                try
                {
                    if (mUserWriterPermissionCach.ContainsKey(user))
                    {
                        return mSuperUsers[user] || (mUserWriterPermissionCach[user].Contains(group));
                    }
                    else
                    {
                        var pps = securityService.GetPermission(user);
                        bool issuerper = false;
                        List<string> mgroups = new List<string>();
                        foreach (var vv in pps)
                        {
                            issuerper = issuerper | vv.SuperPermission;
                            if (vv.Group != null && vv.EnableWrite)
                                mgroups.AddRange(vv.Group);
                        }
                        if (mSuperUsers.ContainsKey(user)) mSuperUsers[user] = issuerper;
                        else mSuperUsers.Add(user, issuerper);
                        mUserWriterPermissionCach.Add(user, mgroups);

                        return mSuperUsers[user] || (mUserReaderPermissionCach[user].Contains(group));
                    }
                }
                catch (Exception ex)
                {
                    LoggerService.Service.Warn("DbInRunWebApi_SecurityManager", ex.Message);
                    return false;
                }
            }

        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="token"></param>
        /// <param name="group"></param>
        /// <returns></returns>
        public bool CheckReaderPermission(string token, string group)
        {

            var securityService = ServiceLocator.Locator.Resolve<IRuntimeSecurity>();
            var user = securityService.GetUserByLoginId(token);

            lock (mSuperUsers)
            {
                try
                {
                    if (mUserReaderPermissionCach.ContainsKey(user))
                    {
                        return mSuperUsers[user] || (mUserReaderPermissionCach[user].Contains(group));
                    }
                    else
                    {
                        var pps = securityService.GetPermission(user);
                        bool issuerper = false;
                        List<string> mgroups = new List<string>();
                        foreach (var vv in pps)
                        {
                            issuerper = issuerper | vv.SuperPermission;
                            if (vv.Group != null)
                                mgroups.AddRange(vv.Group);
                        }

                        if (mSuperUsers.ContainsKey(user)) mSuperUsers[user] = issuerper;
                        else mSuperUsers.Add(user, issuerper);

                        mUserReaderPermissionCach.Add(user, mgroups);

                        return mSuperUsers[user] || (mUserReaderPermissionCach[user].Contains(group));
                    }
                }
                catch (Exception ex)
                {
                    LoggerService.Service.Warn("DbInRunWebApi_SecurityManager", ex.Message);
                    return false;
                }
            }
        }

        #endregion ...Methods...

        #region ... Interfaces ...

        #endregion ...Interfaces...
    }
}
